const Koa = require('koa');
const KoaRouter = require('koa-router');
const koaBodyParser = require('koa-bodyparser');
const query = require('./mysqlAsync');
const { genToken, checkToken } = require('./util');

const app = new Koa();
const router = new KoaRouter();

app.use(koaBodyParser());

// 身份认证中间件
app.use(async (ctx, next) => {
    // 检查是不是要身份认证才能访问的路由
    if (ctx.path === '/login') {
        await next();
        return;
    }
    // ---------------- 认证用户身份 ----------------
    // 1、获取请求中的 token 信息
    const { token } = ctx.headers;
    if (!token) {
        ctx.body = {
            code: 401,
            message: '缺少token字段，无法进行身份认证',
        };
        return;
    }
    // 2、校验 token 是否合法
    try {
        // 校验 token，查看是否合法，如果 token 合法，就能拿到登录时，保存的用户信息
        // 如果校验失败，说明 token 有问题，我们根据捕获的错误类型，来判断该如何响应客户端
        const user = checkToken(token);
        // 放到请求上下文上，方便后面的中间件或接口使用
        ctx.user = user;
    } catch (error) {
        // token 过期的情况
        if (error.name === 'TokenExpiredError') {
            ctx.body = {
                code: 401,
                message: 'token已过期，请重新登录',
            };
            return;
        }
        // token 是伪造的不合法的
        if (error.name === 'JsonWebTokenError') {
            ctx.body = {
                code: 401,
                message: '请老实点，你这 token 不对',
            };
            return;
        }
        // 其他错误类型
        ctx.body = {
            code: 401,
            message: '身份校验失败',
        };
        return;
    }

    // 校验通过，可以放行了
    await next();
});

// 注册：向服务器添加一个用户
router.post('/register', async (ctx) => {
    // 解析请求体
    const { username, password, email = '' } = ctx.request.body;
    // 非空校验
    if (!username || !password) {
        ctx.body = {
            code: 400,
            message: '参数有误',
        };
        return;
    }
    // 如果有邮箱，就校验邮箱格式 53180@qq.com
    if (email && !/^[\w]+@[\w]+\.com/.test(email)) {
        ctx.body = {
            code: 400,
            message: '邮箱格式有误',
        };
        return;
    }
    // 该用户是不是已经在数据库中存在了
    let res = await query(`select * from user where username = '${username}'`);
    // 用户存在，不可以创建
    if (res.length !== 0) {
        ctx.body = {
            code: 403,
            message: '用户已存在，不允许重复创建',
        };
        return;
    }
    // 添加用户信息到数据库
    res = await query(
        `insert into user (username, password, email) values ('${username}', '${password}', '${email}')`
    );
    // 注册成功
    if (res.affectedRows === 1) {
        ctx.body = {
            code: 201,
            message: '注册成功',
        };
    }
});

// 登录：根据用户名密码换取 token 令牌
router.post('/login', async (ctx) => {
    // 解析请求体参数
    const { username, password } = ctx.request.body;
    // 该用户是不是已经在数据库中存在了
    let res = await query(`select * from user where username = '${username}'`);
    // 用户不存在，不能进行登录
    if (res.length === 0) {
        ctx.body = {
            code: 404,
            message: '用户不存在，请先去注册',
        };
        return;
    }
    // 拿到数据库中的这个用户
    const user = res[0];
    // 判断密码是否正确
    if (user.password !== password) {
        ctx.body = {
            code: 401,
            message: '密码不正确',
        };
        return;
    }
    // 生成 json web token
    const token = genToken({ ...user });
    // 返回给客户端
    ctx.body = {
        code: 200,
        data: {
            token,
        },
        message: '登录成功',
    };
});

// 添加收货地址
router.post('/addresses', async (ctx) => {
    // 获取请求体参数
    const { name, mobile, address, is_default = 0 } = ctx.request.body;
    // 是哪个用户发的请求
    const uid = ctx.user.id;
    // 非空校验
    if (!name || !mobile || !address) {
        ctx.body = {
            code: 400,
            message: '缺少必须字段',
        };
        return;
    }
    // is_default 字段是否合法
    if (isNaN(is_default) || ![0, 1].includes(Number(is_default))) {
        ctx.body = {
            code: 400,
            message: '默认地址字段不合法',
        };
        return;
    }
    //  如果是默认地址，需要更新之前的 is_default 为非默认地址
    if (Number(is_default) === 1) {
        await query(
            `update address set is_default = 0 where user_id = ${uid} and is_default = 1`
        );
    }
    // 添加地址
    const res = await query(
        `insert into address (name, mobile, address, is_default, create_time, user_id) values ('${name}', '${mobile}', '${address}', '${is_default}', '${Date.now()}', ${uid})`
    );
    // 添加成功，响应给客户端
    if (res.affectedRows === 1) {
        ctx.body = {
            code: 201,
            message: '添加成功',
        };
    }
});

// 地址列表
router.get('/addresses', async (ctx) => {
    // 获取地址列表
    const res = await query(
        `select * from address where user_id = ${ctx.user.id} order by create_time desc`
    );
    // 响应给客户端
    ctx.body = {
        code: 200,
        data: res,
        message: '请求成功',
    };
});

// 删除地址
router.delete('/addresses/:id', async (ctx) => {
    // 获取路径参数
    const { id } = ctx.params;
    // 直接删除
    const res = await query(`delete from address where id = ${id}`);
    // 删除成功，给予提示
    if (res.affectedRows === 1) {
        ctx.body = {
            code: 204,
            message: '删除成功',
        };
    }
});

app.use(router.routes());

app.listen(8000, () => {
    console.log('启动了');
});
